﻿#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include "RtspClient.h"
#include "Sdp.h"
#include "Log.h"

RtspClient::RtspClient(const char* transport, const char* url):
	m_userAgent("RtspClient"),
	m_transport(transport),
	m_rtspUrl(url)
{
	LOGI("");

	char ip[40] = { 0 };
	uint16_t port = 0;
	char mediaRoute[100] = { 0 };

	if (strncmp(url, "rtsp://", 7) != 0) 
	{
		LOGE("parse Url protocol error");
	}
	if (sscanf(url + 7, "%[^:]:%hu/%s", ip, &port, mediaRoute) == 3) 
	{
	}
	else if (sscanf(url + 7, "%[^/]/%s", ip, mediaRoute) == 2) 
	{
	}
	else 
	{
		LOGE("parse Url compontent error");
	}
	m_ip = ip;
	m_port = port;
	m_mediaRoute = mediaRoute;
	m_sdp = new Sdp;
}

RtspClient::~RtspClient()
{
	LOGI("");
	close(m_fd);

	if (m_sdp) 
	{
		delete m_sdp;
		m_sdp = nullptr;
	}
}

//创建socet，连接服务
bool RtspClient::connectServer() 
{
	LOGI("RtspClient::connectServer：rtspUrl=%s", m_rtspUrl.data());

	m_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_fd < 0)
	{
		LOGE("create socket error");
		return false;
	}

	int on = 1;
	setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));

	sockaddr_in client_addr;
	client_addr.sin_family = AF_INET;
	client_addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(m_fd, (struct sockaddr*)&client_addr, sizeof(struct sockaddr)) < 0)
	{
		LOGE("bind error");
		return false;
	}
	struct sockaddr_in m_server_addr;
	m_server_addr.sin_family = AF_INET;
	m_server_addr.sin_port = htons(m_port);
	inet_pton(AF_INET, m_ip.c_str(), &m_server_addr.sin_addr);

	if (connect(m_fd, (struct sockaddr*)&m_server_addr, sizeof(sockaddr_in)) == -1)
	{
		// LOGE("connect error %d", WSAGetLastError());
		printf("connect error!\n");
		return false;
	}

	return true;
}

void RtspClient::startCmd() 
{
	bool isSendPlay = false;
	int sendCseq = 0; // 与RTSP服务交互过程中Seq的累计值
	int sendTrackNum = 0;

	// RTSP协议交互每次返回的参数解析 start
	int  CSeq = 0;
	char sessionID[50] = { 0 };//从Rtsp响应中获取Session
	int  ResponseStateCode = 0;
	int  ContentLength = 0;
	char ContentBase[100] = { 0 };

	char bufCmdRecv[1000] = { 0 };
	char bufCmdRecvCopy[1000] = { 0 };
	int  bufCmdRecvSize = 0;
	// RTSP协议交互每次返回的参数解析 end

	++sendCseq;
	if (!sendCmdOptions(sendCseq)) //发送option
	{
		return;
	}
	while (true)
	{
		ResponseStateCode = 0;
		CSeq = 0;
		ContentLength = 0;

		//等待接收
		bufCmdRecvSize = recv(m_fd, bufCmdRecv,sizeof(bufCmdRecv), 0);
		if (bufCmdRecvSize <= 0) 
		{
			// LOGE("bufCmdRecv error: %d", WSAGetLastError());
			printf("bufCmdRecv error\n");
			goto FINISH;
		}

		memcpy(bufCmdRecvCopy, bufCmdRecv, bufCmdRecvSize);
		bufCmdRecv[bufCmdRecvSize] = '\0';
		bufCmdRecvCopy[bufCmdRecvSize] = '\0';

		LOGI("bufCmdRecvSize=%d,bufCmdRecv=%s", bufCmdRecvSize, bufCmdRecv);

		const char* sep = "\n";
		char* line = strtok(bufCmdRecv, sep); //字符串分割
		while (line)
		{
			if (strstr(line, "RTSP/1.0")) //字符串查找
			{
				if (sscanf(line, "RTSP/1.0 %d OK\r\n", &ResponseStateCode) != 1) //模式匹配，取出响应码
				{
					LOGE("parse RTSP/1.0 error");
					goto FINISH;
				}
			}
			else if (strstr(line, "Session")) 
			{
				//memset(sessionID, 0, sizeof(sessionID) / sizeof(char));
				if (sscanf(line, "Session: %s\r\n", &sessionID) != 1) //取出会话类型
				{
					LOGE("parse Session error");
					goto FINISH;
				}
				else 
				{
					m_sessionID = sessionID;
				}
			}
			else if (strstr(line, "CSeq")) 
			{
				if (sscanf(line, "CSeq: %d\r\n", &CSeq) != 1) 
				{
					LOGE("parse CSeq error");
					goto FINISH;
				}
			}
			else if (strstr(line, "Content-Base")) 
			{
				if (sscanf(line, "Content-Base: %s\r\n", &ContentBase) != 1) 
				{
					LOGE("parse Content-Base error");
					goto FINISH;
				}
			}
			else if (strstr(line, "Content-length")) 
			{
				if (sscanf(line, "Content-length: %d\r\n", &ContentLength) != 1) 
				{
					LOGE("parse Content-length error");
					goto FINISH;
				}

			}
			line = strtok(NULL, sep);
		}
		if (200 == ResponseStateCode) 
		{
			if (1 == CSeq) 
			{
				// 解析Options，发送Describe
				++sendCseq;
				if (!sendCmdDescribe(sendCseq)) //发送DESCRIBE
				{
					goto FINISH;
				}
			}
			else if (2 == CSeq)
			{
				// 解析Sdp
				m_sdp->parse(bufCmdRecvCopy, bufCmdRecvSize);

				// 发送Setup请求
				SdpTrack* track = m_sdp->popTrack();
				if (track) 
				{
					++sendCseq;
					++sendTrackNum;
					sendCmdSetup(sendCseq, track);
				}
			}
			else if (sendCseq == CSeq && !isSendPlay) 
			{
				// 继续发送Setup请求
				SdpTrack* track = m_sdp->popTrack();
				if (track) 
				{
					++sendCseq;
					++sendTrackNum;
					sendCmdSetup(sendCseq, track);
				}
				else 
				{
					LOGI("发送(%d次)track完成，开始发送Play请求",sendTrackNum);

					++sendCseq;
					if (!sendCmdPlay(sendCseq)) 
					{
						goto FINISH;
					}
					isSendPlay = true;
				}
			}
			else if (sendCseq == CSeq && isSendPlay) 
			{
				LOGI("接收到Play请求的响应");
				parseData(); //进入接收
				goto FINISH;
			}
			else 
			{
				LOGE("CSeq=%d is error", CSeq);
				goto FINISH;
			}
		}
		else 
		{
			LOGE("Rtsp ResponseStateCode=%d is error", ResponseStateCode);
			goto FINISH;
		}
	}

FINISH:
	return;
}

//发送 option
bool RtspClient::sendCmdOptions(int cseq) 
{
	sprintf(m_bufSnd, "OPTIONS rtsp://%s:%d/%s RTSP/1.0\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
bool RtspClient::sendCmdDescribe(int cseq) 
{
	sprintf(m_bufSnd, "DESCRIBE rtsp://%s:%d/%s RTSP/1.0\r\n"
		"Accept: application/sdp\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
bool RtspClient::sendCmdSetup(int cseq, SdpTrack* track) 
{
	int interleaved1 = track->control_id * 2;
	int interleaved2 = interleaved1 + 1;

	sprintf(m_bufSnd, "SETUP rtsp://%s:%d/%s/%s RTSP/1.0\r\n"
		"Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"Session: %s\r\n"
		"\r\n",
		m_ip.data(),m_port, m_mediaRoute.data(), track->control,
		interleaved1,interleaved2,
		cseq,
		m_userAgent.data(),
		m_sessionID.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}

bool RtspClient::sendCmdPlay(int cseq) 
{
	sprintf(m_bufSnd, "PLAY rtsp://%s:%d/%s RTSP/1.0\r\n"
		"Range: npt=0.000-\r\n"
		"CSeq: %d\r\n"
		"User-Agent: %s\r\n"
		"Session: %s\r\n"
		"\r\n",
		m_ip.data(),m_port,m_mediaRoute.data(),
		cseq,
		m_userAgent.data(),
		m_sessionID.data());

	return sendCmdOverTcp(m_bufSnd, strlen(m_bufSnd));
}
//发送请求
bool RtspClient::sendCmdOverTcp(char* buf, size_t size) 
{
	printf("\n\n---------------------------------------\n\n");

	LOGI("size=%lld,buf=%s", size,buf);

	int ret = send(m_fd, buf, size, 0);

	if (ret < 0) 
	{
		// LOGE("send error: %d", WSAGetLastError());
		printf("send error");
		return false;
	}
	return true;
}

void RtspClient::parseData() 
{
	char bufRecv[1000];
	int  bufRecvSize = 0;

	while (true)
	{
		bufRecvSize = recv(m_fd, bufRecv, sizeof(bufRecv), 0);

		if (bufRecvSize <= 0) 
		{
			// LOGE("parseData recv error: %d", WSAGetLastError());
			printf("parseData recv error");
			break;
		}
		else 
		{
			//LOGI("parseData bufRecvSize=%d", bufRecvSize);
		}
	}
}
